﻿using JESAI.Core.Util.Exceptions;
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace JESAI.Core.Exceptions
{
    /// <summary>
    /// JESAI异常
    /// </summary>
    [Serializable]
    public abstract class JESAIException : Exception
    {
        /// <summary>
        /// 空标识
        /// </summary>
        protected const string EmptyFlag = "__EMPTY_FLG";

        /// <summary>
        /// 默认错误消息
        /// </summary>
        protected const string DefaultErrorMessage = "_DEFAULT_ERROR";

        /// <summary>
        /// 默认错误编码
        /// </summary>
        protected const long DefaultErrorCode = 1001;

        /// <summary>
        /// 默认扩展错误编码
        /// </summary>
        protected const long DefaultExtendErrorCode = 1002;

        /// <summary>
        /// 初始化一个<see cref="JESAIException"/>类型的实例
        /// </summary>
        protected JESAIException() : this(DefaultErrorCode, DefaultErrorMessage, EmptyFlag) { }

        /// <summary>
        /// 初始化一个<see cref="JESAIException"/>类型的实例
        /// </summary>
        /// <param name="errorMessage">错误消息</param>
        /// <param name="innerException">内部异常</param>
        protected JESAIException(string errorMessage, Exception innerException = null) : this(errorMessage, EmptyFlag, innerException) { }

        /// <summary>
        /// 初始化一个<see cref="JESAIException"/>类型的实例
        /// </summary>
        /// <param name="errorMessage">错误消息</param>
        /// <param name="flag">错误标识</param>
        /// <param name="innerException">内部异常</param>
        protected JESAIException(string errorMessage, string flag, Exception innerException = null) : this(DefaultExtendErrorCode, errorMessage, flag, innerException) { }

        /// <summary>
        /// 初始化一个<see cref="JESAIException"/>类型的实例
        /// </summary>
        /// <param name="errorCode">错误码</param>
        /// <param name="errorMessage">错误消息</param>
        /// <param name="innerException">内部异常</param>
        protected JESAIException(long errorCode, string errorMessage, Exception innerException = null) : this(errorCode, errorMessage, EmptyFlag, innerException) { }

        /// <summary>
        /// 初始化一个<see cref="JESAIException"/>类型的实例
        /// </summary>
        /// <param name="info">序列化信息</param>
        /// <param name="context">流上下文</param>
        protected JESAIException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
            ExtraData = new Dictionary<string, object>();
            Code = DefaultExtendErrorCode;
            Flag = EmptyFlag;
        }

        /// <summary>
        /// 初始化一个<see cref="JESAIException"/>类型的实例
        /// </summary>
        /// <param name="errorCode">错误码</param>
        /// <param name="errorMessage">错误消息</param>
        /// <param name="flag">错误标识</param>
        /// <param name="innerException">内部异常</param>
        protected JESAIException(long errorCode, string errorMessage, string flag, Exception innerException = null) : base(errorMessage, innerException)
        {
            if (string.IsNullOrWhiteSpace(flag))
                flag = EmptyFlag;
            ExtraData = new Dictionary<string, object>();
            Code = errorCode;
            Flag = flag;
        }

        /// <summary>
        /// 初始化一个<see cref="JESAIException"/>类型的实例
        /// </summary>
        /// <param name="options">JESAI框架异常选项配置</param>
        protected JESAIException(JESAIExceptionOptions options) : base(options.Message, options.InnerException)
        {
            ExtraData = options.ExtraErrors;
            Code = options.ErrorCode;
            Flag = options.Flag;
        }

        /// <summary>
        /// 错误码
        /// </summary>
        public long Code { get; protected set; }

        /// <summary>
        /// 错误标识
        /// </summary>
        public string Flag { get; protected set; }

        /// <summary>
        /// 额外数据
        /// </summary>
        public Dictionary<string, object> ExtraData { get; }

        /// <summary>
        /// 获取完整的消息
        /// </summary>
        public virtual string GetFullMessage() => $"{Code}:({Flag}){Message}";

        /// <summary>
        /// 抛出异常
        /// </summary>
        public virtual void Throw() => ExceptionHelper.PrepareForRethrow(this);
    }
}
